"""
单例模式 - 让一个类只能创建出唯一的实例
    ~ 对象无状态或状态不会发生变化
    ~ 对象有状态，但这些状态是被共享的
实现单例模式
    ~ 通过装饰类的装饰器实现单例
    ~ 通过元类(meta-class)控制对象创建实现单例
元类(type) ---> 类(object) ---> 对象
    ~ ORM框架实现：sqlalchemy / peewee
"""
from functools import wraps
from threading import Lock


def singleton(cls):
    instances = {}
    lock = Lock()

    @wraps(cls)
    def wrapper(*args, **kwargs):
        if cls not in instances:
            with lock:
                if cls not in instances:
                    instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return wrapper


class SingletonMeta(type):

    def __init__(cls, *args, **kwargs):
        cls.__instance = None
        super().__init__(*args, **kwargs)
    
    def __call__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = super().__call__(*args, **kwargs)
        return cls.__instance


# @singleton
# 通过six三方库可以写出2和3兼容的代码
# class President(six.with_metaclass(SingletonMeta, object)):
# class President(metaclass=SingletonMeta):
class President:
    # Python2的写法
    # __metaclass__ = SingletonMeta
    _instance = None
    
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name


p1 = President('王大锤')
p2 = President('李小白')
print(id(p1), id(p2))
print(p1 == p2)
print(p1.name, p2.name)
